home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Applications / NIH Image 1.55 / Source / PlugIns.p < prev    next >
Encoding:
Text File  |  1994-05-04  |  25.6 KB  |  985 lines  |  [TEXT/PJMM]

  1. unit PlugIns;
  2. {This unit for utilizing Adobe Photoshop compatible acquisition, export and filter plug-ins}
  3. {is based on code written by Greg Brown, Steven Gonzalo and Richard Ohlendorf.}
  4. {Ohlendorf Research, Inc.}
  5. {818 LaSalle Street}
  6. {Ottawa, IL 61350}
  7. {815-434-5622}
  8. {Applelink--Abraham@AppleLink.com}
  9.  
  10. interface
  11.     uses
  12.         QuickDraw, Palettes, QDOffscreen, PrintTraps, Globals, utilities, Graphics, Lut, Filters, Stacks, File1, File2;
  13.  
  14.     procedure RunAcqPlugIn (item: integer);
  15.     procedure LoadAcqPlugIn (FileName: str255);
  16.     procedure RunExportPlugIn (item: integer);
  17.     procedure RunFilterPlugIn (item: integer);
  18.     procedure LoadFilterPlugIn (FileName: str255);
  19.  
  20.  
  21. implementation
  22.  
  23.     type
  24.         MonitorRec = record
  25.                 gamma: Fixed;
  26.                 redX: Fixed;
  27.                 redY: Fixed;
  28.                 greenX: Fixed;
  29.                 greenY: Fixed;
  30.                 blueX: Fixed;
  31.                 blueY: Fixed;
  32.                 whiteX: Fixed;
  33.                 whiteY: Fixed;
  34.                 ambient: Fixed;
  35.             end;
  36.  
  37.         PlaneMapType = array[0..15] of integer;
  38.  
  39.         AcquireRecord = record
  40.                 serialNumber: LongInt;
  41.                 abortProc: ProcPtr;
  42.                 progressProc: ProcPtr;
  43.                 maxData: LongInt;
  44.                 imageMode: integer;
  45.                 fImageSize: Point;
  46.                 depth: integer;
  47.                 planes: integer;
  48.                 imageHRes: Fixed;
  49.                 imageVRes: Fixed;
  50.                 rLUT: packed array[0..255] of char;
  51.                 gLUT: packed array[0..255] of char;
  52.                 bLUT: packed array[0..255] of char;
  53.                 data: Ptr;
  54.                 theRect: Rect;
  55.                 loPlane: integer;
  56.                 hiPlane: integer;
  57.                 colBytes: integer;
  58.                 rowBytes: LongInt;
  59.                 planeBytes: LongInt;
  60.                 FileName: Str255;
  61.                 vRefNum: integer;
  62.                 dirty: boolean;
  63.          {Version 4 fields}
  64.                 hostSig: OSType;
  65.                 hostProc: ProcPtr;
  66.                 hostModes: LongInt;
  67.                 planeMap: PlaneMapType;
  68.                 canTranspose: boolean;
  69.                 needTranspose: boolean;
  70.                 duotoneInfo: Handle;
  71.                 diskSpace: LongInt;
  72.                 spaceProc: ProcPtr;
  73.                 monitor: MonitorRec;
  74.                 reserved: packed array[0..255] of char;
  75.             end;
  76.  
  77.         FilterColor = packed array[0..3] of char;
  78.  
  79.         FilterRecord = record
  80.                 serialNumber: LongInt;
  81.                 abortProc: ProcPtr;
  82.                 progressProc: ProcPtr;
  83.                 parameters: Handle;
  84.                 fImageSize: Point;
  85.                 planes: integer;
  86.                 filterRect: Rect;
  87.                 background: RGBColor;
  88.                 foreground: RGBColor;
  89.                 maxSpace: LongInt;
  90.                 bufferSpace: LongInt;
  91.                 inRect: Rect;
  92.                 inLoPlane: integer;
  93.                 inHiPlane: integer;
  94.                 outRect: Rect;
  95.                 outLoPlane: integer;
  96.                 outHiPlane: integer;
  97.                 inData: Ptr;
  98.                 inRowBytes: LongInt;
  99.                 outData: Ptr;
  100.                 outRowBytes: LongInt;
  101.                 isFloating: boolean;
  102.                 haveMask: boolean;
  103.                 autoMask: boolean;
  104.                 maskRect: Rect;
  105.                 maskData: Ptr;
  106.                 maskRowBytes: LongInt;
  107.          {Version 4 fields}
  108.                 backColor: FilterColor;
  109.                 foreColor: FilterColor;
  110.                 hostSig: OSType;
  111.                 hostProc: ProcPtr;
  112.                 imageMode: integer;
  113.                 imageHRes: Fixed;
  114.                 imageVRes: Fixed;
  115.                 floatCoord: Point;
  116.                 wholeSize: Point;
  117.                 monitor: MonitorRec;
  118.                 reserved: packed array[0..255] of char;
  119.             end;
  120.  
  121.  
  122.         ExportRecord = record
  123.                 serialNumber: LongInt;
  124.                 abortProc: ProcPtr;
  125.                 progressProc: ProcPtr;
  126.                 maxData: LongInt;
  127.                 imageMode: integer;
  128.                 eImageSize: Point;
  129.                 depth: integer;
  130.                 planes: integer;
  131.                 imageHRes: Fixed;
  132.                 imageVRes: Fixed;
  133.                 rLUT: packed array[0..255] of char;
  134.                 gLUT: packed array[0..255] of char;
  135.                 bLUT: packed array[0..255] of char;
  136.                 theRect: Rect;
  137.                 loPlane: integer;
  138.                 hiPlane: integer;
  139.                 data: Ptr;
  140.                 rowBytes: LongInt;
  141.                 filename: Str255;
  142.                 vRefNum: integer;
  143.                 dirty: BOOLEAN;
  144.                 selectBBox: Rect;
  145.         {Version 4 fields }
  146.                 hostSig: OSType;
  147.                 hostProc: ProcPtr;
  148.                 duotoneInfo: Handle;
  149.                 thePlane: integer;
  150.                 monitor: MonitorRec;
  151.                 reserved: packed array[0..255] of char;
  152.             end;
  153.  
  154.  
  155.     var
  156.         acqData, exportData, filterData, nlines, rowpix: LongInt;
  157.         disppict, srcpict: ptr;
  158.         refnum: integer;
  159.         ShowProgress: boolean;
  160.         ProgressMsg: string[17];
  161.         FilterRec: FilterRecord;
  162.  
  163.  
  164.     procedure DummyProc;
  165.     begin
  166.     end;
  167.  
  168.     function TestAbort: boolean;
  169.     begin
  170.         if commandperiod then
  171.             testabort := true
  172.         else
  173.             testabort := false;
  174.     end;
  175.  
  176.  
  177.     procedure UpdateProgress (done, total: LongInt);
  178.         var
  179.             whatpercent: integer;
  180.     begin
  181.         if ShowProgress and (done > 0) and (total > 0) and (total >= done) then begin
  182.                 whatpercent := round((done / total) * 100);
  183.                 UpdateMeter(whatpercent, ProgressMsg);
  184.             end;
  185.     end;
  186.  
  187.  
  188.  
  189.     procedure CopyData (src: ptr; theRect: rect; srcRowBytes, dstRowBytes: LongInt; lines: integer);
  190.         var
  191.             i: integer;
  192.             dst: ptr;
  193.             width: LongInt;
  194.     begin
  195.         with theRect do
  196.             width := right - left;
  197.         with info^ do
  198.             dst := ptr(ord4(PicBaseAddr) + LongInt(therect.top) * BytesPerRow + therect.left);
  199.         for i := 0 to lines - 1 do begin
  200.                 BlockMove(src, dst, width);
  201.                 src := ptr(ord4(src) + srcRowBytes);
  202.                 dst := ptr(ord4(dst) + dstRowBytes);
  203.             end;
  204.     end;
  205.  
  206.  
  207.     procedure CopyInterleavedRGBData (src: ptr; theRect: rect; srcRowBytes, dstRowBytes, colBytes: LongInt; lines: integer; planeMap: PlaneMapType);
  208.         var
  209.             i, j, slice, plane, width: integer;
  210.             src2, src3, dst2, dst3: ptr;
  211.     begin
  212.         with theRect do
  213.             width := right - left;
  214.         with info^.StackInfo^ do
  215.             for slice := 1 to 3 do begin
  216.                     CurrentSlice := slice;
  217.                     SelectSlice(slice);
  218.                     plane := planeMap[slice - 1];
  219.                     src2 := src;
  220.                     dst2 := ptr(ord4(info^.PicBaseAddr) + LongInt(therect.top) * info^.BytesPerRow + therect.left);
  221.                     for i := 0 to lines - 1 do begin
  222.                             src3 := ptr(ord4(src2) + plane);
  223.                             dst3 := dst2;
  224.                             for j := 0 to width - 1 do begin
  225.                                     dst3^ := src3^;
  226.                                     src3 := ptr(ord4(src3) + colBytes);
  227.                                     dst3 := ptr(ord4(dst3) + 1);
  228.                                 end;
  229.                             src2 := ptr(ord4(src2) + srcRowBytes);
  230.                             dst2 := ptr(ord4(dst2) + dstRowBytes);
  231.                         end; {for i:=1 to nlines-1}
  232.                 end; {for slice:=1 to 3}
  233.     end;
  234.  
  235.  
  236.     procedure CopyPlanarRGBData (src: ptr; theRect: rect; srcRowBytes, dstRowBytes, planeBytes: LongInt; lines, loPlane, hiPlane: integer);
  237.         var
  238.             i, j, slice, plane: integer;
  239.             src2, dst2: ptr;
  240.             width: LongInt;
  241.     begin
  242.         with theRect do
  243.             width := right - left;
  244.         if loPlane = hiPlane then
  245.             planeBytes := 0;
  246.         if (planeBytes < 0) or (planeBytes > srcRowBytes) then
  247.             planeBytes := width;
  248.         with info^.StackInfo^ do
  249.             for plane := loPlane to hiPlane do begin
  250.                     slice := plane + 1;
  251.                     if slice > 3 then
  252.                         slice := 3;
  253.                     CurrentSlice := slice;
  254.                     SelectSlice(slice);
  255.                     src2 := ptr(ord4(src) + planeBytes * plane);
  256.                     dst2 := ptr(ord4(info^.PicBaseAddr) + LongInt(therect.top) * info^.BytesPerRow + therect.left);
  257.                     for i := 0 to lines - 1 do begin
  258.                             BlockMove(src2, dst2, width);
  259.                             src2 := ptr(ord4(src2) + srcRowBytes);
  260.                             dst2 := ptr(ord4(dst2) + dstRowBytes);
  261.                         end;
  262.                 end;
  263.     end;
  264.  
  265.  
  266.     function MakeRGBStack (name: str255; width, height: integer): boolean;
  267.         var
  268.             ignore: integer;
  269.     begin
  270.         MakeRGBStack := false;
  271.         if not NewPicWindow('RGB', width, height) then
  272.             exit(MakeRGBStack);
  273.         if not MakeStackFromWindow then
  274.             exit(MakeRGBStack);
  275.         if not AddSlice(false) then begin
  276.                 info^.changes := false;
  277.                 ignore := CloseAWindow(info^.wptr);
  278.                 exit(MakeRGBStack);
  279.             end;
  280.         if not AddSlice(false) then begin
  281.                 info^.changes := false;
  282.                 ignore := CloseAWindow(info^.wptr);
  283.                 exit(MakeRGBStack);
  284.             end;
  285.         MakeRGBStack := true;
  286.     end;
  287.  
  288.     procedure GetSFCurDir (var vRefNum: integer; var DirID: LongInt);
  289.   {From "Inside Macintosh:Files", page 3-31.}
  290.         type
  291.             IntPtr = ^integer;
  292.             LongIntPtr = ^LongInt;
  293.         const
  294.             SFSaveDisk = $214;
  295.             CurDirStore = $398;
  296.     begin
  297.         vRefNum := -IntPtr(SFSaveDisk)^;
  298.         DirID := LongIntPtr(CurDirStore)^;
  299.     end;
  300.  
  301.     procedure SetSFCurDir (vRefNum: integer; DirID: LongInt);
  302.         type
  303.             IntPtr = ^integer;
  304.             LongIntPtr = ^LongInt;
  305.         const
  306.             SFSaveDisk = $214;
  307.             CurDirStore = $398;
  308.     begin
  309.         IntPtr(SFSaveDisk)^ := -vRefNum;
  310.         LongIntPtr(CurDirStore)^ := dirID;
  311.     end;
  312.  
  313.  
  314.     function isSystem7: boolean;
  315.     begin
  316.         if not System7 then {These routines uses File Manager calls only available under System 7.}
  317.             PutMessage('System 7 required to use plug-ins.');
  318.         isSystem7 := System7;
  319.     end;
  320.  
  321.  
  322.     procedure LoadCodeResource (FileName: str255; fType: osType; var codePtr: ProcPtr);
  323.         var
  324.             myReply: StandardFileReply;
  325.             myTypes: SFTypeList;
  326.             err: OSErr;
  327.             CodeResource: handle;
  328.             GotSpec: boolean;
  329.             spec: FSSpec;
  330.             SaveVol: integer;
  331.             SaveDir: LongInt;
  332.     begin
  333.         GotSpec := false;
  334.         if FileName <> '' then begin
  335.                 err := FSMakeFSSpec(PluginsVRefNum, PluginsDirID, FileName, spec);
  336.                 GotSpec := err = noerr;
  337.             end;
  338.         if not GotSpec then begin
  339.                 GetSFCurDir(SaveVol, SaveDir);
  340.                 if PluginsVRefNum <> 0 then
  341.                     SetSFCurDir(PluginsVRefNum, PluginsDirID);
  342.                 myTypes[0] := fType;
  343.                 StandardGetFile(nil, 1, myTypes, myReply);
  344.                 if myReply.sfGood then begin
  345.                         spec := myReply.sfFile;
  346.                         FileName := myReply.sfFile.name;
  347.                         GotSpec := true
  348.                     end;
  349.                 GetSFCurDir(PluginsVRefNum, PluginsDirID);
  350.                 SetSFCurDir(SaveVol, SaveDir);
  351.             end;
  352.         if GotSpec then begin
  353.                 refnum := FSpOpenResFile(spec, fsCurPerm);
  354.                 if (refnum <> -1) then begin
  355.                         if fType = '8BAM' then begin {Acquistion plug-in}
  356.                                 if pos('Raster', FileName) <> 0 then {Can't show progress indicator if RasterOps frame grabber.}
  357.                                     ShowProgress := false;
  358.                                 if FileName <> LastAcqPlugIn then
  359.                                     acqData := 0;
  360.                                 LastAcqPlugIn := FileName;
  361.                             end
  362.                         else if fType = '8BFM' then begin  {Filter plug-in}
  363.                                 if FileName <> LastFilterPlugIn then begin
  364.                                         filterData := 0;
  365.                                         FilterRec.parameters := nil;
  366.                                     end;
  367.                                 LastFilterPlugIn := FileName;
  368.                             end
  369.                         else if fType = '8BEM' then begin  {Export plug-in}
  370.                                 if FileName <> LastExportPlugIn then
  371.                                     exportData := 0;
  372.                                 LastExportPlugIn := FileName;
  373.                             end;
  374.                         UseResFile(refnum);
  375.                         codeResource := GetIndResource(fType, 1);
  376.                         hlock(codeResource);
  377.                         codePtr := ProcPtr(codeResource^);
  378.                     end
  379.                 else
  380.                     PutMessage(concat('Error opening plug-in. (Code=', Long2Str(ResError), ')'));
  381.             end;
  382.     end;
  383.  
  384.  
  385.     procedure CallCode (selector: integer; AcqRec: ptr; var data: LongInt; var result: Integer; codePtr: ProcPtr);
  386.     inline
  387.         $205F,   {move.l (a7)+,a0}
  388.         $4E90;   {jsr (a0)}
  389.  
  390.  
  391.     procedure LoadAcqPlugIn (FileName: str255);
  392.  
  393.         const
  394.             AcquireAbout = 0;
  395.             AcquireStart = 1;
  396.             AcquireContinue = 2;
  397.             AcquireFinish = 3;
  398.             AcquirePrepare = 4;
  399.  
  400.             BitMapMode = 0;
  401.             GrayScaleMode = 1;
  402.             IndexedColorMode = 2;
  403.             RGBColorMode = 3;
  404.  
  405.         var
  406.             thiserror: qderr;
  407.             codePtr: ProcPtr;
  408.             AcqRec: acquirerecord;
  409.             result, i, selector, width, height, ignore: integer;
  410.             ok: boolean;
  411.             dst: ptr;
  412.             name: str255;
  413.  
  414.         procedure ShowInfo (str: str255);
  415.         begin
  416.             with AcqRec do
  417.                 if ControlKeyDown then begin
  418.                         str := concat(str, cr, cr, 'imageMode=', long2str(imageMode));
  419.                         str := concat(str, cr, 'width=', long2str(therect.right - therect.left));
  420.                         str := concat(str, cr, 'height=', long2str(therect.bottom - therect.top));
  421.                         str := concat(str, cr, 'depth=', long2str(depth));
  422.                         str := concat(str, cr, 'planes=', long2str(planes));
  423.                         str := concat(str, cr, 'colBytes=', long2str(colBytes));
  424.                         str := concat(str, cr, 'rowBytes=', long2str(rowBytes));
  425.                         str := concat(str, cr, 'planeBytes=', long2str(planeBytes));
  426.                         str := concat(str, cr, 'planeMap=', long2str(planeMap[0]), ' ', long2str(planeMap[1]), long2str(planeMap[2]), ' ', long2str(planeMap[3]));
  427.                         str := concat(str, cr, 'loPlane=', long2str(loPlane));
  428.                         str := concat(str, cr, 'hiPlane=', long2str(hiPlane));
  429.                         ShowMessage(str);
  430.                     end;
  431.         end;
  432.  
  433.         procedure CopyLUT;
  434.             var
  435.                 i: integer;
  436.         begin
  437.             with info^ do begin
  438.                     for i := 0 to 255 do
  439.                         with cTable[i], cTable[i].rgb, AcqRec do begin
  440.                                 value := 0;
  441.                                 red := bsl(ord(rLUT[255 - i]), 8);
  442.                                 green := bsl(ord(gLUT[255 - i]), 8);
  443.                                 blue := bsl(ord(bLUT[255 - i]), 8);
  444.                             end;
  445.                     LoadLUT(cTable);
  446.                     SetupPseudocolor;
  447.                     LutMode := ColorLUT;
  448.                     IdentityFunction := false;
  449.                     UpdateMap;
  450.                 end
  451.         end;
  452.  
  453.         procedure abort (error: integer; started: boolean);
  454.             var
  455.                 msg: str255;
  456.         begin
  457.             if started then
  458.                 CallCode(AcquireFinish, @AcqRec, acqData, result, codePtr);
  459.             CloseResFile(RefNum);
  460.             if MeterWindow <> nil then begin
  461.                     DisposeWindow(MeterWindow);
  462.                     MeterWindow := nil;
  463.                 end;
  464.             if error < 0 then begin
  465.                     msg := '';
  466.                     if error = -108 then
  467.                         msg := concat(cr, cr, '"', 'Not enough memory', '"');
  468.                     PutMessage(concat('Plug-in error (result code=', long2str(error), ')', msg));
  469.                 end;
  470.             PicLeft := PicLeftBase;
  471.             PicTop := PicTopBase;
  472.             macro := false;
  473.             exit(LoadAcqPlugIn);
  474.         end;
  475.  
  476.     begin
  477.         if not isSystem7 then
  478.             exit(LoadAcqPlugIn);
  479.         ShowProgress := true;
  480.         codePtr := nil;
  481.         LoadCodeResource(FileName, '8BAM', codePtr);
  482.         if codePtr = nil then
  483.             exit(LoadAcqPlugIn);
  484.         with AcqRec do begin
  485.                 SerialNumber := 12345;
  486.                 AbortProc := @TestAbort;
  487.                 ProgressProc := @UpdateProgress;
  488.                 MaxData := maxBlock div 2;
  489.                 if MaxData < 25000 then begin
  490.                         PutMessage('Out of memory.');
  491.                         abort(0, false);
  492.                     end;
  493.                 imageHRes := 0;
  494.                 hostSig := 'Imag';
  495.                 hostProc := @DummyProc;
  496.                 hostModes := 14;{=1110, i.e., grayscale, indexed color and RGB}
  497.                 for i := 0 to 15 do begin
  498.                         planemap[i] := i;
  499.                     end;
  500.                 FileName := '';
  501.                 canTranspose := false;
  502.                 needTranspose := false;
  503.                 duoToneInfo := nil;
  504.                 diskSpace := -1;
  505.                 spaceProc := nil;
  506.                 monitor.gamma := 0;
  507.                 for i := 0 to 255 do
  508.                     reserved[i] := chr(0);
  509.             end;
  510.         ProgressMsg := 'Acquiring Image…';
  511.         ShowInfo('Acquire');
  512.         CallCode(AcquirePrepare, @AcqRec, acqData, result, codePtr);
  513.         if (result <> 0) then
  514.             abort(result, false);
  515.         ShowInfo('start');
  516.         CallCode(AcquireStart, @AcqRec, acqData, result, codePtr);{call main dialog box etc.}
  517.         if (result <> 0) then
  518.             abort(result, false);
  519.         if AcqRec.depth = 1 then begin
  520.                 PutMessage('NIH Image does not support acquisition of bitmap (black and white) images.');
  521.                 abort(0, true);
  522.             end;
  523.         ShowInfo('Opening');
  524.         OpeningPlugInWindow := true; {Causes MakeNewWindow to open window offscreen.}
  525.         if AcqRec.ImageMode = RGBColorMode then
  526.             ok := MakeRGBStack('Untitled', AcqRec.fImageSize.h, AcqRec.fImageSize.v)
  527.         else begin
  528.                 if FileName <> '' then
  529.                     name := FileName
  530.                 else
  531.                     name := 'Untitled';
  532.                 ok := NewPicWindow(name, AcqRec.fImageSize.h, AcqRec.fImageSize.v);
  533.             end;
  534.         OpeningPlugInWindow := false;
  535.         if not ok then begin
  536.                 ShowInfo('Aborting');
  537.                 abort(0, true);
  538.             end;
  539.         with info^, AcqRec do
  540.             if ImageMode = GrayScaleMode then begin
  541.                     if LUTMode = ColorLUT then
  542.                         ResetGrayMap
  543.                 end
  544.             else if ImageMode = RGBColorMode then
  545.                 ResetGrayMap
  546.             else if ImageMode = IndexedColorMode then begin
  547.                     ShowInfo('CopyLUT');
  548.                     CopyLUT;
  549.                 end;
  550.         ShowWatch;
  551.         repeat
  552.       {ShowInfo('Continue');}
  553.             CallCode(AcquireContinue, @AcqRec, acqData, result, codePtr);
  554.             if result <> 0 then begin
  555.                     info^.changes := false;
  556.                     ignore := CloseAWindow(info^.wptr);
  557.                     abort(result, true);
  558.                 end;
  559.             with AcqRec do
  560.                 if data <> nil then begin
  561.                         width := therect.right - therect.left;
  562.                         height := therect.bottom - therect.top;
  563.              {ShowInfo('Continue');}
  564.                         with Info^ do
  565.                             if ((therect.left + width) <= PixelsPerLine) and (therect.top < nlines) then begin
  566.                                     if (ImageMode = RGBColorMode) and (planes >= 3) and ((hiPlane - loPlane) < 3) then begin
  567.                                             if planeBytes = 1 then
  568.                                                 CopyInterleavedRGBData(data, theRect, rowBytes, Info^.BytesPerRow, colBytes, height, planeMap)
  569.                                             else
  570.                                                 CopyPlanarRGBData(data, theRect, rowBytes, Info^.BytesPerRow, planeBytes, height, loPlane, hiPlane)
  571.                                         end
  572.                                     else
  573.                                         CopyData(data, theRect, rowBytes, Info^.BytesPerRow, height);
  574.                                 end;
  575.                     end;
  576.         until (result <> 0) or (AcqRec.data = nil);
  577.         CallCode(AcquireFinish, @AcqRec, acqData, result, codePtr);
  578.         CloseResFile(RefNum);
  579.         if MeterWindow <> nil then begin
  580.                 DisposeWindow(MeterWindow);
  581.                 MeterWindow := nil;
  582.             end;
  583.         MoveWindow(info^.wptr, PicLeft, PicTop, true);
  584.         if AcqRec.imageHRes <> 0 then
  585.             with info^ do begin
  586.                     xSpatialScale := FixRound(AcqRec.imageHRes);
  587.                     ySpatialScale := xSpatialScale;
  588.                     PixelAspectRatio := 1.0;
  589.                     xUnit := 'inch';
  590.                     SpatiallyCalibrated := true;
  591.                     UpdateTitleBar;
  592.                 end;
  593.         if info^.StackInfo <> nil then
  594.             with info^.StackInfo^ do begin
  595.                     for i := nSlices downto 1 do begin
  596.                             CurrentSlice := i;
  597.                             SelectSlice(CurrentSlice);
  598.                             InvertPic;
  599.                         end;
  600.                     UpdateTitleBar;
  601.                     ConvertRGBToEightBitColor(true);
  602.                 end
  603.         else
  604.             InvertPic;
  605.         if AcqRec.ImageMode = IndexedColorMode then begin
  606.                 FixColors;
  607.                 WhatToUndo := NothingToUndo;
  608.             end;
  609.         Info^.changes := true;
  610.     end; {LoadAcqPlugIn}
  611.  
  612.  
  613.     procedure PutPlugInMsg (str: str255);
  614.         var
  615.             str2: str255;
  616.     begin
  617.         if System7 then
  618.             PutMessage(concat(str, ' plug-ins found. Plug-ins must be in a folder named "Plug-ins" located in either the same folder as NIH Image or in the System Folder.'))
  619.         else
  620.             PutMessage('System 7 required to use plug-ins.');
  621.     end;
  622.  
  623.  
  624.     procedure RunAcqPlugIn (item: integer);
  625.         var
  626.             name: str255;
  627.     begin
  628.         if nAcqPlugIns = 0 then begin
  629.                 PutPlugInMsg('No acquisition');
  630.                 exit(RunAcqPlugIn);
  631.             end;
  632.         GetItem(AcquireMenuH, item, name);
  633.         LoadAcqPlugIn(name);
  634.     end;
  635.  
  636.  
  637.     procedure LoadExportPlugIn (FileName: str255);
  638.  
  639.         const
  640.             ExportAbout = 0;
  641.             ExportStart = 1;
  642.             ExportContinue = 2;
  643.             ExportFinish = 3;
  644.             ExportPrepare = 4;
  645.  
  646.             BitMapMode = 0;
  647.             GrayScaleMode = 1;
  648.             IndexedColorMode = 2;
  649.             RGBColorMode = 3;
  650.  
  651.         var
  652.             thiserror: qderr;
  653.             codePtr: ProcPtr;
  654.             ExportRec: ExportRecord;
  655.             result, i, selector, width, height: integer;
  656.             ok: boolean;
  657.             dst: ptr;
  658.             roi, empty: rect;
  659.             offset: LongInt;
  660.  
  661.         procedure ShowInfo (str: str255);
  662.         begin
  663.             with ExportRec do
  664.                 if ControlKeyDown then begin
  665.                         str := concat(str, cr, cr, 'imageMode=', long2str(imageMode));
  666.                         str := concat(str, cr, 'width=', long2str(therect.right - therect.left));
  667.                         str := concat(str, cr, 'height=', long2str(therect.bottom - therect.top));
  668.                         str := concat(str, cr, 'depth=', long2str(depth));
  669.                         str := concat(str, cr, 'planes=', long2str(planes));
  670.                         str := concat(str, cr, 'rowBytes=', long2str(rowBytes));
  671.                         str := concat(str, cr, 'loPlane=', long2str(loPlane));
  672.                         str := concat(str, cr, 'hiPlane=', long2str(hiPlane));
  673.                         ShowMessage(str);
  674.                     end;
  675.         end;
  676.  
  677.         function BadRect: boolean;
  678.         begin
  679.             BadRect := false;
  680.             with info^.PicRect do begin
  681.                     if (ExportRec.theRect.left < left) or (exportRec.theRect.right > right) or (exportRec.theRect.top < top) or (exportRec.theRect.bottom > bottom) then
  682.                         BadRect := true;
  683.                 end;
  684.         end;
  685.  
  686.         procedure abort (result: integer);
  687.         begin
  688.             CloseResFile(RefNum);
  689.             if MeterWindow <> nil then begin
  690.                     DisposeWindow(MeterWindow);
  691.                     MeterWindow := nil;
  692.                 end;
  693.             InvertPic;
  694.             if result < 0 then
  695.                 PutMessage(concat('Plug-in error(result code=', long2str(result), ').'));
  696.             exit(LoadExportPlugIn);
  697.         end;
  698.  
  699.     begin
  700.         if not isSystem7 then
  701.             exit(LoadExportPlugIn);
  702.         SetRect(empty, 0, 0, 0, 0);
  703.         with info^ do
  704.             if RoiShowing then
  705.                 roi := RoiRect
  706.             else
  707.                 roi := empty;
  708.         ShowProgress := true;
  709.         codePtr := nil;
  710.         LoadCodeResource(FileName, '8BEM', codePtr);
  711.         if codePtr = nil then
  712.             exit(LoadExportPlugIn);
  713.         InvertPic;
  714.         with ExportRec, info^ do begin
  715.                 SerialNumber := 12345;
  716.                 AbortProc := @TestAbort;
  717.                 ProgressProc := @UpdateProgress;
  718.                 MaxData := maxBlock div 2;
  719.                 if MaxData < 25000 then begin
  720.                         PutMessage('Out of memory.');
  721.                         abort(0);
  722.                     end;
  723.                 if LUTMode = Grayscale then
  724.                     ImageMode := GrayScaleMode
  725.                 else
  726.                     ImageMode := IndexedColorMode;
  727.                 with PicRect, eImageSize do begin
  728.                         h := right - left;
  729.                         v := bottom - top;
  730.                     end;
  731.                 depth := 8;
  732.                 planes := 1;
  733.                 imageHRes := bsl(72, 16);
  734.                 imageVRes := imageHRes;
  735.                 for i := 0 to 255 do
  736.                     with cTable[i].rgb do begin
  737.                             rLUT[255 - i] := chr(bsr(red, 8));
  738.                             gLUT[255 - i] := chr(bsr(green, 8));
  739.                             bLUT[255 - i] := chr(bsr(blue, 8));
  740.                         end;
  741.                 theRect := empty;
  742.                 loPlane := 0;
  743.                 hiPlane := 0;
  744.                 data := PicBaseAddr;
  745.                 rowBytes := BytesPerRow;
  746.                 FileName := title;
  747.                 vRefNum := vRef;
  748.                 dirty := changes;
  749.                 selectBBox := roi;
  750.                 hostSig := 'Imag';
  751.                 hostProc := @DummyProc;
  752.                 duoToneInfo := nil;
  753.                 thePlane := 0;
  754.                 monitor.gamma := 0;
  755.                 for i := 0 to 255 do
  756.                     reserved[i] := chr(0);
  757.             end;
  758.         ProgressMsg := 'Exporting Image…';
  759.         CallCode(ExportPrepare, @ExportRec, ExportData, result, codePtr);
  760.         if (result <> 0) then
  761.             abort(result);
  762.         CallCode(ExportStart, @ExportRec, ExportData, result, codePtr);{call main dialog box etc.}
  763.         if (result <> 0) then
  764.             abort(result);
  765.         ShowWatch;
  766.         repeat
  767.             if BadRect then
  768.                 abort(0);
  769.             with ExportRec, info^ do begin
  770.                     offset := LongInt(theRect.top) * BytesPerRow + theRect.left;
  771.                     data := ptr(ord4(PicBaseAddr) + offset);
  772.                 end;
  773.             CallCode(exportContinue, @exportRec, exportData, result, codePtr);
  774.         until (result <> 0) or EmptyRect(exportRec.theRect);
  775.         CallCode(ExportFinish, @ExportRec, ExportData, result, codePtr);
  776.         CloseResFile(RefNum);
  777.         if MeterWindow <> nil then begin
  778.                 DisposeWindow(MeterWindow);
  779.                 MeterWindow := nil;
  780.             end;
  781.         InvertPic;
  782.     end;
  783.  
  784.  
  785.     procedure RunExportPlugIn (item: integer);
  786.         var
  787.             name: str255;
  788.     begin
  789.         if nExportPlugIns = 0 then begin
  790.                 PutPlugInMsg('No export');
  791.                 exit(RunExportPlugIn);
  792.             end;
  793.         GetItem(ExportMenuH, item, name);
  794.         LoadExportPlugIn(name);
  795.     end;
  796.  
  797.  
  798.     procedure LoadFilterPlugIn (FileName: str255);
  799.  
  800.         const
  801.             filterAbout = 0;
  802.             filterParameters = 1;
  803.             filterPrepare = 2;
  804.             filterStart = 3;
  805.             filterContinue = 4;
  806.             filterFinish = 5;
  807.  
  808.             GrayScaleMode = 1;
  809.  
  810.         var
  811.             thiserror: qderr;
  812.             codePtr: ProcPtr;
  813.             result, i, selector, width, height: integer;
  814.             ok: boolean;
  815.             dst: ptr;
  816.             Empty, roi: rect;
  817.             offset: LongInt;
  818.  
  819.         procedure InvertUndoPic;
  820.             var
  821.                 tPort: GrafPtr;
  822.                 SaveGDevice: GDHandle;
  823.         begin
  824.             SaveGDevice := GetGDevice;
  825.             SetGDevice(osGDevice);
  826.             GetPort(tPort);
  827.             with UndoInfo^ do begin
  828.                     SetPort(GrafPtr(osPort));
  829.                     InvertRect(PicRect);
  830.                 end;
  831.             SetPort(tPort);
  832.             SetGDevice(SaveGDevice);
  833.         end;
  834.  
  835.         procedure abort;
  836.         begin
  837.             CloseResFile(RefNum);
  838.             InvertPic;
  839.             InvertUndoPic;
  840.             if MeterWindow <> nil then begin
  841.                     DisposeWindow(MeterWindow);
  842.                     MeterWindow := nil;
  843.                 end;
  844.             exit(LoadFilterPlugIn);
  845.         end;
  846.  
  847.         function BadRect: boolean;
  848.         begin
  849.             BadRect := false;
  850.             with info^.PicRect do begin
  851.                     if (FilterRec.inRect.left < left) or (FilterRec.inRect.right > right) or (FilterRec.inRect.top < top) or (FilterRec.inRect.bottom > bottom) then
  852.                         BadRect := true;
  853.                     if (FilterRec.outRect.left < left) or (FilterRec.outRect.right > right) or (FilterRec.outRect.top < top) or (FilterRec.outRect.bottom > bottom) then
  854.                         BadRect := true;
  855.                 end;
  856.         end;
  857.  
  858.     begin {LoadFilterPlugIn}
  859.         if not isSystem7 then
  860.             exit(LoadFilterPlugIn);
  861.         if macro then
  862.             if FileName = 'Reset' then begin
  863.                     FilterRec.parameters := nil;
  864.                     exit(LoadFilterPlugIn);
  865.                 end;
  866.         if NotInBounds or NoUndo or NotRectangular then
  867.             exit(LoadFilterPlugIn);
  868.         with info^ do
  869.             if RoiShowing then
  870.                 roi := RoiRect
  871.             else
  872.                 roi := PicRect;
  873.         KillRoi;
  874.         SetupUndo;
  875.         SetupUndoInfoRec;
  876.         InvertPic;
  877.         InvertUndoPic;
  878.         WhatToUndo := UndoFilter;
  879.         ShowProgress := true;
  880.         codePtr := nil;
  881.         LoadCodeResource(FileName, '8BFM', codePtr);
  882.         if codePtr = nil then
  883.             exit(LoadFilterPlugIn);
  884.         SetRect(Empty, 0, 0, 0, 0);
  885.         with FilterRec, info^ do begin
  886.                 serialnumber := 12345;
  887.                 AbortProc := @TestAbort;
  888.                 ProgressProc := @UpdateProgress;
  889.                 with PicRect, fImageSize do begin
  890.                         h := right - left;
  891.                         v := bottom - top;
  892.                     end;
  893.                 planes := 1;
  894.                 filterRect := roi;
  895.                 background := WhiteRGB;
  896.                 foreground := BlackRGB;
  897.                 maxSpace := PixMapSize;
  898.                 bufferSpace := 0;
  899.                 inRect := Empty;
  900.                 inLoPlane := 0;
  901.                 inHiPlane := 0;
  902.                 outRect := Empty;
  903.                 outLoPlane := 0;
  904.                 outHiPlane := 0;
  905.                 inData := UndoBuf;
  906.                 inRowBytes := BytesPerRow;
  907.                 outData := PicBaseAddr;
  908.                 outRowBytes := BytesPerRow;
  909.                 isFloating := false;
  910.                 haveMask := false;
  911.                 autoMask := false;
  912.                 maskRect := Empty;
  913.                 maskData := nil;
  914.                 maskRowBytes := BytesPerRow;
  915.                 for i := 0 to 3 do begin
  916.                         backColor[i] := chr(BackgroundIndex);
  917.                         foreColor[i] := chr(ForegroundIndex);
  918.                     end;
  919.                 hostSig := 'Imag';
  920.                 hostProc := @DummyProc;
  921.                 imageMode := GrayScaleMode;
  922.                 imageHRes := bsl(72, 16);
  923.                 imageVRes := imageHRes;
  924.                 floatCoord.h := 0;
  925.                 floatCoord.v := 0;
  926.                 wholeSize := fImageSize;
  927.                 monitor.gamma := 0;
  928.                 for i := 0 to 255 do
  929.                     reserved[i] := chr(0);
  930.             end;
  931.         ProgressMsg := 'Filtering Image…';
  932.         if not (macro and (FilterRec.parameters <> nil)) then begin
  933.                 CallCode(FilterParameters, @FilterRec, filterData, result, codePtr);
  934.                 if result <> 0 then
  935.                     abort;
  936.             end;
  937.         CallCode(FilterPrepare, @FilterRec, filterData, result, codePtr);
  938.         if result <> 0 then
  939.             abort;
  940.         if FilterRec.bufferSpace > (MaxBlock + MinFree) then begin
  941.                 PutMessage('Not enough memory to run filter.');
  942.                 abort;
  943.             end;
  944.         CallCode(FilterStart, @FilterRec, filterData, result, codePtr);
  945.         if result <> 0 then
  946.             abort;
  947.         ShowWatch;
  948.         repeat
  949.             if BadRect then
  950.                 abort;
  951.             with FilterRec, info^ do begin
  952.                     offset := LongInt(inRect.top) * BytesPerRow + inRect.left;
  953.                     inData := ptr(ord4(UndoBuf) + offset);
  954.                     offset := LongInt(outRect.top) * BytesPerRow + outRect.left;
  955.                     outData := ptr(ord4(PicBaseAddr) + offset);
  956.                 end;
  957.             CallCode(filterContinue, @FilterRec, filterData, result, codePtr);
  958.         until (result <> 0) or (EmptyRect(FilterRec.inRect) and EmptyRect(FilterRec.outRect));
  959.         CallCode(filterFinish, @FilterRec, filterData, result, codePtr);
  960.         CloseResFile(RefNum);
  961.         if MeterWindow <> nil then begin
  962.                 DisposeWindow(MeterWindow);
  963.                 MeterWindow := nil;
  964.             end;
  965.         InvertPic;
  966.         InvertUndoPic;
  967.         UpdatePicWindow;
  968.         info^.changes := true;
  969.     end;
  970.  
  971.  
  972.     procedure RunFilterPlugIn (item: integer);
  973.         var
  974.             name: str255;
  975.     begin
  976.         if nFilterPlugIns = 0 then begin
  977.                 PutPlugInMsg('No filter');
  978.                 exit(RunFilterPlugIn);
  979.             end;
  980.         GetItem(FilterMenuH, item, name);
  981.         LoadFilterPlugIn(name);
  982.     end;
  983.  
  984.  
  985. end.